package pri.hillchen.springbootstd.bms.common.base;

import com.alibaba.fastjson.JSON;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import pri.hillchen.springbootstd.bms.entity.system.AccessLog;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author:hillchen
 * @DESCRIPTION:
 * @Date: Created in 17:09 2017/10/20 0020.
 */
public class ControllerProxy implements MethodInterceptor {
    private Object sourceBean;

    public ControllerProxy(Object sourceBean) {
        this.sourceBean = sourceBean;
    }

    public Object getSourceBean() {
        return sourceBean;
    }

    private Map<Method,Method> sourceProxyMethodMap = new ConcurrentHashMap<Method,Method>();

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if(method.isAnnotationPresent(RequestMapping.class)){
            /**
             * 获取当前request上下文，如果不存在则表示该RequestMapping方法不是在通过http请求后调用的
             */
            ServletRequestAttributes ra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            AccessLog accessLog = new AccessLog();
            if(ra !=null){
                beforeIvoke(accessLog,ra);
                Method sourceMethod = getSourceMethod(method);
                try{
                    Object result = sourceMethod.invoke(sourceBean,objects);
                    afterIvoke(accessLog);
                    return result;
                }catch (Exception e){
                    errorIvoke(accessLog,e);
                    throw e;
                }finally {
                    finallyIvoke(accessLog);
                }
            }


        }
        return methodProxy.invokeSuper(o, objects);
    }

    private HttpServletRequest getCurrentRequest(){
        ServletRequestAttributes ra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if(ra != null){
            return ra.getRequest();
        }
        return null;
    }

    private Method getSourceMethod(Method proxyMethod)throws Throwable{
        if(sourceProxyMethodMap.containsKey(proxyMethod)){
            return sourceProxyMethodMap.get(proxyMethod);
        }else{
            Method sourceMethod = sourceBean.getClass().getMethod(proxyMethod.getName(),proxyMethod.getParameterTypes());
            sourceProxyMethodMap.put(proxyMethod,sourceMethod);
            return sourceMethod;
        }
    }

    private void beforeIvoke(AccessLog accessLog,ServletRequestAttributes ra ){
        System.out.println("beforeIvoke");
        HttpServletRequest request = getCurrentRequest();
        accessLog.setAccessUrl(request.getRequestURL().toString());
        accessLog.setAccessTime(new Date());
        accessLog.setAccessParameter(JSON.toJSON(request.getParameterMap()).toString());
    }

    private void afterIvoke(AccessLog accessLog ){
        System.out.println("afterIvoke");
        accessLog.setAnswerType(0);
        accessLog.setAnswerTime(new Date());
    }

    private void errorIvoke(AccessLog accessLog,Throwable throwable){
        accessLog.setAnswerType(1);
        accessLog.setErrorMsg("请求处理异常:"+throwable.getMessage());
        accessLog.setAnswerTime(new Date());
    }
    private void finallyIvoke(AccessLog accessLog){
        //将请求日志对象推送到日志队列中
        LogHelper.logEnqueue(accessLog);
System.out.println(accessLog);
    }
}
